package st.business.tepth.ic;

import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.util.Log;

import org.greenrobot.eventbus.EventBus;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

import cc.lotuscard.ILotusCallBack;
import cc.lotuscard.LotusCardDriver;
import cc.lotuscard.LotusCardParam;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.ObservableSource;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import st.business.tepth.business.event.ICEvent;
import st.shadow.library.core.Shadow;

import static android.content.Context.USB_SERVICE;
import static cc.lotuscard.LotusCardDriver.m_InEndpoint;
import static cc.lotuscard.LotusCardDriver.m_OutEndpoint;
import static cc.lotuscard.LotusCardDriver.m_UsbDeviceConnection;

/**
 * @author zhangyu
 * @date 2018/5/14
 */

public class LotusCard implements ICInterface, ILotusCallBack {
    public static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
    private UsbDeviceConnection m_LotusCardDeviceConnection = null;
    private static final int m_nVID = 1306;
    private static final int m_nPID = 20763;
    private static UsbDevice m_LotusCardDevice = null;
    private boolean isClose = false;
    private Disposable mDisposable;


    private LotusCardDriver mLotusCardDriver;
    private long mDeviceHandle;

    public LotusCard() {
        setUsbCallBack();
        mLotusCardDriver = new LotusCardDriver();
        LotusCardDriver.m_lotusCallBack = this;
    }

    @Override
    public void openDevice() {
        isClose = false;
        Observable.create(new ObservableOnSubscribe<Object>() {
            @Override
            public void subscribe(ObservableEmitter<Object> e) throws Exception {
                mDeviceHandle = mLotusCardDriver.OpenDevice("", 0, 0, 0, 0,// 使用内部默认超时设置
                        true);
                if (mDeviceHandle != -1) {
                    if (!mLotusCardDriver.Beep(mDeviceHandle, 10)) {
                        EventBus.getDefault().post(new OpenIcEvent(false, "蜂鸣器唤醒失败,\n请重新打卡", ""));
                        e.onError(new Throwable("call beep failed"));
                    } else {
                        EventBus.getDefault().post(new OpenIcEvent(false, "蜂鸣器唤醒成功", "蜂鸣器唤醒成功"));
                        e.onNext(new Object());
                    }
                } else {
                    EventBus.getDefault().post(new OpenIcEvent(false, "设备打开失败", "设备打开失败"));
                    e.onError(new Throwable("mDeviceHandle is -1"));
                }
            }
        }).observeOn(Schedulers.io())
                .subscribeOn(Schedulers.io())
                .subscribe(new Observer<Object>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }

                    @Override
                    public void onNext(Object o) {
                        searchCard();
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("Throwable", e.getMessage());
                    }

                    @Override
                    public void onComplete() {
                        Log.e("onComplete", "onComplete");
                    }
                });
    }


    @Override
    public void searchCard() {
        final int nRequestType = LotusCardDriver.RT_ALL;
        Observable.create(new ObservableOnSubscribe<Object>() {
            @Override
            public void subscribe(ObservableEmitter<Object> e) throws Exception {
                LotusCardParam tLotusCardParam1 = new LotusCardParam();
                if (mLotusCardDriver.GetCardNo(mDeviceHandle, nRequestType,
                        tLotusCardParam1)) {
                    if (mLotusCardDriver.Authentication(mDeviceHandle,
                            LotusCardDriver.AM_A, 1, tLotusCardParam1)) {
                        byte[] data = new byte[48];
                        for (int i = 0; i < 3; i++) {
                            if (mLotusCardDriver.Read(mDeviceHandle, 4 + i, tLotusCardParam1)) {
                                int j = i * 16;
                                for (int k = 0; k < 16; k++) {
                                    data[j++] = tLotusCardParam1.arrBuffer[k];
                                }
                                if (i >= 2) {
                                    int len = 0;
                                    for (int m = data.length - 1; m >= 0; m--) {
                                        if (data[m] != 0) {
                                            len = m;
                                            break;
                                        }
                                    }
                                    final byte[] finalData = new byte[len + 1];
                                    System.arraycopy(data, 0, finalData, 0, finalData.length);
                                    String[] result = analysisData(new String(finalData));
                                    if (result != null && result.length >= 2) {
                                        EventBus.getDefault().post(new ICEvent(result[0], result[1]));
                                    }
                                }
                            }
                        }

                    }
                } else {
                    EventBus.getDefault().post(new ICEvent(null, null));
                }
                e.onComplete();
            }
        })
                .repeatWhen(new Function<Observable<Object>, ObservableSource<?>>() {
                    @Override
                    public ObservableSource<?> apply(Observable<Object> objectObservable) throws Exception {
                        return objectObservable.flatMap(new Function<Object, ObservableSource<?>>() {
                            @Override
                            public ObservableSource<?> apply(Object o) throws Exception {
                                if (isClose) {
                                    return Observable.error(new Throwable("关闭主界面"));
                                }
                                return Observable.just(1).delay(500, TimeUnit.MILLISECONDS);
                            }
                        });
                    }
                })
                .observeOn(Schedulers.io())
                .subscribeOn(Schedulers.io())
                .subscribe(new Observer<Object>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        mDisposable = d;
                    }

                    @Override
                    public void onNext(Object o) {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {
                    }
                });
    }

    @Override
    public void closeDevice() {
        isClose = true;
        if (mDisposable != null) {
            mDisposable.dispose();
        }
    }

    @Override
    public void leisureDevice() {
    }

    @Override
    public boolean callBackExtendIdDeviceProcess(Object objUser, byte[] arrBuffer) {
        return false;
    }

    @Override
    public boolean callBackReadWriteProcess(long nDeviceHandle, boolean bRead, byte[] arrBuffer) {
        int nResult = 0;
        boolean bResult = false;
        int nBufferLength = arrBuffer.length;
        int nWaitCount = 0;
        if (null == m_UsbDeviceConnection)
            return false;
        if (null == m_OutEndpoint)
            return false;
        if (null == m_InEndpoint)
            return false;
        if (nBufferLength < 65)
            return false;
        if (bRead) {
            arrBuffer[0] = 0;
            while (true) {
                nResult = m_UsbDeviceConnection.bulkTransfer(m_InEndpoint,
                        arrBuffer, 64, 1000);
                if (nResult <= 0)
                    break;
                if (arrBuffer[0] != 0) {
                    //此处调整一下
                    System.arraycopy(arrBuffer, 0, arrBuffer, 1, nResult);
                    arrBuffer[0] = (byte) nResult;
                    break;
                }
                nWaitCount++;
                if (nWaitCount > 1000)
                    break;
            }
            // AddLog("m_InEndpoint bulkTransfer Read:"+nResult);
            bResult = nResult == 64;
        } else {
            nResult = m_UsbDeviceConnection.bulkTransfer(m_OutEndpoint,
                    arrBuffer, 64, 1000);
            bResult = nResult == 64;
        }
        return bResult;
    }

    private boolean setUsbCallBack() {
        UsbManager m_UsbManager = (UsbManager) Shadow.getApplication().getSystemService(USB_SERVICE);
        if (null == m_UsbManager)
            return false;
        HashMap<String, UsbDevice> deviceList = m_UsbManager.getDeviceList();
        if (!deviceList.isEmpty()) {
            for (UsbDevice device : deviceList.values()) {
                if ((m_nVID == device.getVendorId())
                        && (m_nPID == device.getProductId())) {
                    m_LotusCardDevice = device;
                    //m_strDeviceNode = m_LotusCardDevice.getDeviceName();
                    break;
                }
            }
        }
        if (null == m_LotusCardDevice)
            return false;
        UsbInterface m_LotusCardInterface = m_LotusCardDevice.getInterface(0);
        UsbDeviceConnection conn = null;
        if (m_UsbManager.hasPermission(m_LotusCardDevice)) {
            conn = m_UsbManager.openDevice(m_LotusCardDevice);
        }

        if (null == conn)
            return false;

        if (conn.claimInterface(m_LotusCardInterface, true)) {
            m_LotusCardDeviceConnection = conn;
        } else {
            conn.close();
        }
        if (null == m_LotusCardDeviceConnection)
            return false;
        // 把上面获取的对性设置到接口中用于回调操作
        m_UsbDeviceConnection = m_LotusCardDeviceConnection;
        if (m_LotusCardInterface.getEndpoint(1) != null) {
            m_OutEndpoint = m_LotusCardInterface.getEndpoint(1);
        }
        if (m_LotusCardInterface.getEndpoint(0) != null) {
            m_InEndpoint = m_LotusCardInterface.getEndpoint(0);
        }
        return true;
    }

    private String[] analysisData(String data) {
        String result;
        try {
            result = AESUtils.code_desEncrypt(data);
            if (result.isEmpty()) {
                return null;
            }
            String[] results = result.split("_");
            if (result.length() < 2) {
                return null;
            }
            return results;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}
